----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    10:14:28 11/14/2010 
-- Design Name: 
-- Module Name:    led_control - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity led_control is
    Port ( 	--Data_In : in  STD_LOGIC_VECTOR( 7 downto 0);
			--Data_Out : out  STD_LOGIC_VECTOR( 7 downto 0);
			--Addr_In : in  STD_LOGIC_VECTOR( 4 downto 0);
			LED_IN : in std_logic_vector(7 downto 0);
			
			MODE_In : in std_logic_vector(7 downto 0);
			VALUE_In : in std_logic_vector(7 downto 0);
			Clock_In : in STD_LOGIC;  
			RESET_In : in std_logic;
			Led_Out : out  STD_LOGIC_VECTOR( 7 downto 0));		  
end led_control;

architecture Behavioral of led_control is
	
--constants
--constant LED_MODE_WREGISTER : std_logic_vector(4 downto 0) := "00001"; --01 component select --01 mode register
--constant LED_VALUE_WREGISTER : std_logic_vector(4 downto 0) := "00010"; --01 component select --01 value register
--constant LED_MODE_RREGISTER : std_logic_vector(4 downto 0) := "10001"; --01 component select --11 read mode register
--constant LED_VALUE_RREGISTER : std_logic_vector(4 downto 0) := "10010"; --01 component select --11 read value register
--constant LED_GET_STATUS_MSG : std_logic_vector(4 downto 0) := "10100"; --0 trigger status message to be sent

--modes
--00 static led display  --value = led lights on
--01 inverse led display --value = led lights off
--02 normal cycle fade in and out --value = speed of shift
--03 ping pong fade in and out --value = speed of shift

signal led_sig : std_logic_vector(7 downto 0) := x"00";
signal mode_reg : std_logic_vector(7 downto 0) := x"00";
signal value_reg : std_logic_vector(7 downto 0) := x"00";

--LED PROCESS--
signal ping_pong_en : std_logic := '1';
signal shift_right_en : std_logic := '0';	
signal clock_fade : std_logic:='0';
signal led_en : std_logic_vector(7 downto 0) := "00000001"; --to enable static "0000000" to enable dynamic set Led_en to whatever bits you want on
signal shift_en : std_logic_vector(7 downto 0) := "00000000"; -- to enable static "0000000" 
signal cntDiv : std_logic_vector(15 downto 0) := "0000000000000000"; --counter
type typeIntArray is array(7 downto 0) of integer range 0 to 255;
   -- Intensity for each LED: 0 = off, 255 = full on.
signal cmpPwm: typeIntArray:=(1,1,1,1,1,1,1,1); --to enable static 'on' set to 511 
signal idlePwm: typeIntArray:=(0,0,0,0,0,0,0,0);
constant ckPwmRange: integer:= 7; --50MHz/512 ~ 92KHz
signal cnt_en : std_logic_vector(7 downto 0) := "11111111"; --cnt_en enables the fade up or down
signal int_en : std_logic_vector(7 downto 0):= "11111111"; --int_en = 1 fade up =0 fade down
   -- LSB in the cntPwm alias of cntDiv
alias cntPwm: std_logic_vector(7 downto 0) is cntDiv(7+ckPwmRange downto ckPwmRange);

begin
	
	Led_Out <= led_sig;
	mode_reg <= Mode_In;
	value_reg <= VALUE_In;

	
	ckDivider: process(Clock_In,Reset_In)
	begin
		if Clock_In'event and Clock_In='1' then
			cntDiv <= cntDiv + '1';
			
		end if;
	end process;

	--BUFG_inst1 : BUFG
   --port map (
   --   O => clock_fade,     	-- Clock buffer output
   --   I => cntDiv(12)   -- Clock buffer input
   --);
	
	clock_fade <= cntDiv(12);
	
	Fadder: process( clock_fade,Reset_In)
	begin
		for i in 0 to 7 loop           			-- for each LED
			if clock_fade'event and clock_fade='1' and led_en(i) = '1' then 
				shift_en(i) <= '0';				
				if cnt_en(i) = '1' and int_en(i) = '1' then         
					-- coresponding switch ON, not yet full intensity
					cmpPwm(i) <= cmpPwm(i)+1;     -- increasing intensity
				elsif cnt_en(i) = '1' and int_en(i) = '0' then --and led_en(i) = '0' then 
					-- coresponding switch OFF, not yet full dark
					cmpPwm(i) <= cmpPwm(i)-1;     -- decreasing intensity
				end if;
				if cmpPwm(i) = 255 then
					cnt_en(i) <= '0';
					idlePwm(i) <= idlePwm(i) + 1;
					cmpPwm(i) <= cmpPwm(i);
					int_en(i) <= '0';
					if(idlePwm(i) = 1) then
						idlePwm(i) <= 0;
						cnt_en(i) <= '1';
						cmpPwm(i) <= cmpPwm(i)-1;     -- decreasing intensity
					end if;
				end if;
				if cmpPwm(i) = 0 then
					--led_en(i) <= '1';
					cnt_en(i) <= '1';
					int_en(i) <= '1';
					--idlePwm(i) <= idlePwm(i) + 1;
					--if(idlePwm(i) = 2047) then
						--idlePwm(i) <= 0;
						--cnt_en(i) <= '1';
						shift_en(i) <= '1';
						cmpPwm(i) <= cmpPwm(i) + 1;     -- increasing intensity
					--end if;
				end if;		
				if Reset_In = '1' then
					cnt_en(i) <= '1';
					int_en(i) <= '1';
					shift_en(i) <= '0';
					cmpPwm(i) <= 1;
				end if;
			end if;
		end loop;
	end process;
	
	
	
	process(clock_fade,Reset_In)
	begin
		if clock_fade'event and clock_fade='1' then 
			shift_right_en <= shift_right_en;
			if (ping_pong_en = '1' and shift_en(7) = '1') then
				shift_right_en <= '1';
				led_en <= led_en(0) & led_en(7 downto 1);
			elsif(ping_pong_en ='1' and shift_en(0) = '1') then
				shift_right_en <= '0';
				led_en <= led_en(6 downto 0) & led_en(7);
			end if;
			if(shift_right_en = '0' and ( shift_en(6)= '1' or shift_en(5)= '1' or shift_en(4)= '1' or shift_en(3)= '1'
				or shift_en(2)= '1' or shift_en(1)= '1' ) and shift_en(0) = '0' and shift_en(7) = '0') then
				led_en <= led_en(6 downto 0) & led_en(7);
			elsif(shift_right_en = '1' and ( shift_en(6)= '1' or shift_en(5)= '1' or shift_en(4)= '1' or shift_en(3)= '1'
				or shift_en(2)= '1' or shift_en(1)= '1')and shift_en(0) = '0' and shift_en(7) = '0') then
				led_en <= led_en(0) & led_en(7 downto 1);
			end if;
			if RESET_In = '1' then
				led_en <= "00000001";
			end if;
		end if;
	end process;
	
	PWM: process(cntPwm, cmpPwm,RESET_In)
	begin
		for i in 0 to 7 loop         	-- for each LED
			if (conv_integer(cntPwm) + conv_integer(2)) < cmpPwm(i) then
				-- counter value less than reference
				led_sig(i) <= '1';          -- LED ON
			else 
				-- counter value greater than reference
				led_sig(i) <= '0';          -- LED OFF
			end if;
			if(RESET_In = '1') then
				led_sig(i) <= '0';
			end if;
		end loop;
	end process;


		
end Behavioral;

